package com.yhq.basic.jvm.dataarea;

import java.util.stream.Stream;

/**
 * 场景一：动态年龄,
 * 场景二：对象在Eden区分配，若新对象无法在Eden区分配，触发MinorGC，触发之后还是无法存放该对象，
 * 则会把Eden存活的对象先放入Old区，然后再分配
 * 案例：
 * @author hqyin
 * @date 2024/8/8 2:21 PM
 */
public class Demo7DynamicAge {
    public static void main(String[] args) {
        //测试-对象在Eden区分配
//        test_ObjEden();
        //测试-动态年龄
        test_DynamicAge();
    }

    /**
     * 动态年龄
     * 前言：
     * -XX:+PrintTenturingDistribution 让JVM在每次Minor GC之后打出Survivor空间中对象的年龄分布
     *
     * -XX:InitialTenuringThreshold 表示对象被移动到老年代的年龄阈值的初始值，本机默认值为7。
     *该参数在第一次Minor GC时用于判断对象是否需要移动到老年代。
     *
     * -XX:MaxTenuringThreshold 表示对象被移动到老年代的年龄阈值的最大值，默认值为15。这个参数是给Serial收集器
     * 和没有开启UseAdaptiveSizePolicy的ParNew GC收集器用的，对于PSGC而言，第一次以InitialTenuringThreshold（默认值为7）来算，
     * 之后的MinorGC会动态估算（另外，也会根据TargetSurvivorRatio来动态计算晋升阈值）。
     *
     * -XX:TargetSurvivorRatio 表示Minor GC结束后Survivor区域中占用空间的期望比例
     * 实际上新生代的对象并不一定是达到该值才会晋升到老年代，而是动态地计算实际的晋升阈值tenuring threshold。
     *
     * 计算规则：
     * 期望Survivor空间(Desired survivor size) = 单个Survivor区的实际大小 * -XX:TargetSurvivorRatio
     * JVM会将每个对象的年龄信息、每个年龄段对象的总大小记录在“age table”表中。按照age table中年龄从小到大排，
     * 如果所有小于等于某个age值的对象占用空间大于Desired survivor size，则最新的晋升阈值即为age和MaxTenuringThreshold两者的最小值
     *
     * 案例：案例：-Xmx15m -Xms15m -XX:TargetSurvivorRatio=10 -XX:+PrintTenuringDistribution -XX:+UseSerialGC -XX:+PrintGCDetails
     * TODO:测试失败
     */
    private static void test_DynamicAge() {
        // 设置 JVM 参数
//        System.setProperty("sun.rmi.dgc.server.gcInterval", "3600000"); // 设置 RMI 垃圾收集间隔时间，防止立即 GC
        // 创建一个可以快速填满 Survivor 区域的对象流
        Stream.generate(Demo7DynamicAge::createObject).limit(1000000).count();
        // 触发 GC
        System.gc();

    }

    /**
     * 场景：对象在Eden区分配，若新对象无法在Eden区分配，触发MinorGC，触发之后还是无法存放该对象，
     * 则会把Eden存活的对象先放入Old区，然后再分配
     * 案例：-Xmx15m -Xms15m -XX:+PrintGCDetails
     */
    private static void test_ObjEden() {
        byte[] allocation1 = new byte[1*1024*1024];
        byte[] allocation2 = new byte[1*1024*1024];
        byte[] allocation3 = new byte[1*1024*1024];
    }

    private static Foo createObject() {
        return new Foo();
    }

    static class Foo {
        byte[] bytes = new byte[1024];
    }
}
